//控制游戏逻辑
(function(window) {
    function getRand(min, max) { //定义一个随机函数
        return Math.floor(Math.random() * (max - min + 1) + min);
    }

    function sort(arr, uname, val) {
        let l = 0,
            r = arr.length - 1,
            mid;
        while (l <= r) {
            mid = (l + r) >> 1;
            if (val > arr[mid].score) r = mid - 1;
            if (val < arr[mid].score) l = mid + 1;
            if (val === arr[mid].score) { l = mid; break }
        }
        arr.splice(l, 0, { name: uname, score: val }); //在l位置，删除0个元素，然后将val添加到l开始的位置
    }
    let that = null;
    let scoreTab = null;
    let rankList = null;
    let keyD, keyU;
    let gameMode = 0;
    class Game extends Render { //游戏控制器对象
        constructor(width, height, bgColor, x, y) {
            super(width, height, bgColor, x, y);
            this.snake = new Snake();
            this.food = new Food(this.snake.width, this.snake.height);
            this.map = new Map(this.snake.width, this.snake.height);
            this.gameCount = -1; //游戏重开次数
            this.usr = '';
            this.userList = [];
            this.rankNameList = [];
            this.rankScoreList = [];
            this.timer = null;
            this.paused = false;
            that = this;
        }
        initial(mode) {
            gameMode = mode;
            this.snake.initial();
            this.food.initial(this.snake.width, this.snake.height);
            this.map.initial(this.snake.width, this.snake.height);
            this.timer = null;
            this.paused = false;
        }
        createFood() {
            this.food.repos(getRand(this.map.x, (this.map.x + this.map.width - this.food.width) / this.food.width), getRand(this.map.y, (this.map.y + this.map.height - this.food.height) / this.food.height));
        }
        getUser() {
            this.usr = prompt(`请输入您的尊姓大名:`);
            this.usr = this.usr ? this.usr : 'Unknown';
        }
        start() {
            //渲染游戏开始的画面
            this.getUser();
            this.score = 0;
            this.spaceLock = 0;
            this.keyLock = 0;
            rankList = document.querySelector('aside');
            rankList.style.display = 'none';
            this.map.render();
            scoreTab = document.querySelector('.scoreTab');
            scoreTab.style.display = 'block';
            scoreTab.innerHTML = `积分：${this.score}`;
            this.createFood();
            this.food.render();
            this.snake.render();
            this.snakeAutoMove();
            this.bindKey();
        }
        snakeAutoMove() {
            if (this.timer) clearInterval(this.timer);
            if (this.spaceLock) this.snake.speed *= 5;
            this.timer = setInterval(function() {
                this.snake.move();
                this.keyLock = 0;
                let snakeHead = this.snake.body[0];
                //判断蛇头的位置是否合法，是否吃到食物
                let flag = 0;
                switch (gameMode) {
                    case 0:
                        for (let i = 1; i < this.snake.body.length; i++) //判断是否吃到自己
                            if (snakeHead.x === this.snake.body[i].x && snakeHead.y === this.snake.body[i].y) {
                                this.gameover(); //吃到自己则游戏结束                        
                                return;
                            }
                    case 1:

                        for (let i = 1; i < this.snake.body.length; i++) {
                            //  吃到自己则切断后面的身体     
                            if (snakeHead.x === this.snake.body[i].x && snakeHead.y === this.snake.body[i].y) {
                                flag = i;
                            }
                            if (flag) {
                                this.snake.body[i].remove();
                            }
                        }
                        break;
                }
                this.snake.body.length = flag || this.snake.body.length;
                if (snakeHead.x < 0 || snakeHead.y < 0 || Math.abs(snakeHead.x - this.map.width / snakeHead.width) < 0.000001 || Math.abs(snakeHead.y - this.map.height / snakeHead.height) < 0.000001) { //判断是否出界
                    this.gameover();
                    return;
                }
                if (snakeHead.x === this.food.x && snakeHead.y === this.food.y) { //判断是否吃到食物
                    this.snake.grow();
                    this.snake.render();
                    this.createFood();
                    this.food.render();
                    this.score++;
                    if (parseInt(this.score / 5) + 1 !== this.snake.rank) {
                        ++this.snake.rank;
                        this.snake.speed = (this.snake.rank - 1) * 0.1 + 1;
                        this.snakeAutoMove();
                    }
                    scoreTab.innerHTML = `积分：${this.score}`;
                } else {
                    this.snake.render();
                }
            }.bind(that), (400 / this.snake.speed));
        }
        bindKey() {
            keyD = pressKey.bind(that);
            keyU = releaseKey.bind(that);
            document.addEventListener('keydown', keyD);
            document.addEventListener('keyup', keyU);
        }
        removeBind() {
            document.removeEventListener('keydown', keyD);
            document.removeEventListener('keyup', keyU);
        }
        gameover() {
            clearInterval(this.timer);
            alert('Game over...');
            alert(`可喜可贺您的最终积分达到了${this.score}分!`);
            let olNameDom = document.querySelector('.rankNameList');
            let olScoreDom = document.querySelector('.rankScoreList');
            for (let i = 0; i < this.rankNameList.length; i++) {
                olNameDom.removeChild(this.rankNameList[i]);
                olScoreDom.removeChild(this.rankScoreList[i]);
            }
            sort(this.userList, this.usr, this.score);
            for (let i = 0; i < this.userList.length; i++) {
                let li = document.createElement('li');
                li.innerHTML = `${i+1}.  ${this.userList[i].name}`;
                olNameDom.appendChild(li);
                this.rankNameList.push(li);
                li = document.createElement('li');
                li.innerHTML = `${this.userList[i].score}`;
                olScoreDom.appendChild(li);
                this.rankScoreList.push(li);
            }
            this.map.remove();
            this.food.remove();
            this.snake.remove();
            this.removeBind();
            scoreTab.style.display = 'none';
            rankList.style.display = 'block';
            return
        }
    }
    let pressKey = function(e) {
        if (!this.keyLock && !this.paused) {
            switch (e.keyCode) {
                case 37: //左
                    if (this.snake.direction !== 'right') {
                        this.snake.direction = 'left';
                        this.keyLock = 1;
                    }
                    break;
                case 38: //上
                    if (this.snake.direction !== 'down') {
                        this.snake.direction = 'up';
                        this.keyLock = 1;
                    }
                    break;
                case 39: //右
                    if (this.snake.direction !== 'left') {
                        this.snake.direction = 'right';
                        this.keyLock = 1;
                    }
                    break;
                case 40: //下
                    if (this.snake.direction !== 'up') {
                        this.snake.direction = 'down';
                        this.keyLock = 1;
                    }
                    break;
                case 32: //加速
                    if (!this.spaceLock) {
                        this.spaceLock = 1;
                        this.snakeAutoMove();
                    }
                    break;
            }
        }
    };
    let releaseKey = function(e) {
        if (e.keyCode === 27) {
            if (!this.paused) {
                clearInterval(this.timer);
            } else {
                this.snakeAutoMove();
            }
            this.paused = !this.paused;
        }
        if (e.keyCode === 32 && !this.paused) {
            this.spaceLock = 0;
            this.snake.speed /= 5;
            this.snakeAutoMove();
        }
    };
    window.Game = Game;
}(window))